#include "Vigenere.h"
using namespace Encriptacion;

Vigenere::Vigenere(string claveParaEncriptar) {

	this->claveParaEncriptar = claveParaEncriptar;
}

bool Vigenere::abrirArchivo(fstream& archivo, string path, bool crearNuevo) {

	if (crearNuevo)
		archivo.open(path.c_str(), ios::out | ios::trunc);
	else
		archivo.open(path.c_str(), ios::in | ios::out);

	if (archivo.bad()) {
		archivo.open(path.c_str(), ios::in | ios::out);
	}

	return (!archivo.bad());
}

string Vigenere::generarArchivoEncriptado(string pathDelArchivo, int tipoReporte) {

	bool termine = false;

	// abro el archivo a encriptar, creo y abro el archivo encriptado
//	string pathDelArchivoEncriptado = "ArchivoEncriptado.txt";
	fstream archivoAEncriptar;
	fstream archivoEncriptado;

	this->abrirArchivo(archivoAEncriptar, pathDelArchivo, false);
	string pathDelArchivoEncriptado = getPathArchivoEncriptacionPorTipoReporte(tipoReporte);
	this->abrirArchivo(archivoEncriptado, pathDelArchivoEncriptado, true);

	// creo los bloques para encriptar
	int tamanioBloque = this->claveParaEncriptar.length();
	char* bloqueLeido = new char[tamanioBloque];
	char* bloqueAGuardar = new char[tamanioBloque];

	while (!termine) {

		int cantidadDeCaracteresLeidos = 0;
		// leo hasta <tamanioBloque> caracteres o hasta q sea EOF
		while (cantidadDeCaracteresLeidos < tamanioBloque
				&& !archivoAEncriptar.eof()) {

			archivoAEncriptar.get(bloqueLeido[cantidadDeCaracteresLeidos]);
			cantidadDeCaracteresLeidos++;
		}

		// si llegué al EOF y el bloqueLeido no se llenó, agrego un caracter de fin
		if (cantidadDeCaracteresLeidos < tamanioBloque) {
			bloqueLeido[cantidadDeCaracteresLeidos] = '@';
			termine = true;
		}

		// aplico la encriptación --> E = (m + c) MOD 256
		for (int i = 0; i < tamanioBloque; i++) {

			if (bloqueLeido[i] != '@')
				bloqueAGuardar[i] = (bloqueLeido[i]
						+ claveParaEncriptar.at(i)) % 256;
			else{
				termine = true;
				tamanioBloque = i-1;
				break;
			}
		}

		archivoEncriptado.write(bloqueAGuardar, tamanioBloque);
	}

	archivoAEncriptar.close();
	archivoEncriptado.close();

	delete bloqueLeido;
	delete bloqueAGuardar;

	return pathDelArchivoEncriptado;
}

string Vigenere::generarArchivoDesencriptado(string pathDelArchivo,
		int tipoReporte) {

	bool termine = false;

	// abro el archivo a desencriptar, creo y abro el archivo desencriptado
	fstream archivoADesencriptar;
	fstream archivoDesencriptado;
	this->abrirArchivo(archivoADesencriptar, pathDelArchivo, false);
//	string pathDelArchivoDesencriptado = "ArchivoDesencriptado.txt";
	string pathDelArchivoDesencriptado = getPathArchivoDesencriptacionPorTipoReporte(tipoReporte);
	this->abrirArchivo(archivoDesencriptado, pathDelArchivoDesencriptado, true);

	// creo los bloques para desencriptar
	int tamanioBloque = this->claveParaEncriptar.length();
	char* bloqueLeido = new char[tamanioBloque];
	char* bloqueAGuardar = new char[tamanioBloque];

	while (!termine) {

		int cantidadDeCaracteresLeidos = 0;

		// leo hasta <tamanioBloque> caracteres o hasta q sea EOF o hasta que encuentre el caracter de corte
		while (cantidadDeCaracteresLeidos < tamanioBloque
				&& !archivoADesencriptar.eof()) {

			archivoADesencriptar.get(bloqueLeido[cantidadDeCaracteresLeidos]);
			cantidadDeCaracteresLeidos++;
		}

		// si llegué al EOF y el bloqueLeido no se llenó, agrego un caracter de fin
		if (cantidadDeCaracteresLeidos < tamanioBloque) {
			bloqueLeido[cantidadDeCaracteresLeidos] = '@';
			termine = true;
		}

		// aplico la desencriptación
		for (int i = 0; i < tamanioBloque; i++) {
			if (bloqueLeido[i] != '@') {
				bloqueAGuardar[i] = ((bloqueLeido[i] - claveParaEncriptar.at(i))) % 256;
			} else{
				termine =true;
				tamanioBloque = i -1;
				break;
			}
		}

		archivoDesencriptado.write(bloqueAGuardar, tamanioBloque);
	}

	archivoADesencriptar.close();
	archivoDesencriptado.close();

	delete bloqueLeido;
	delete bloqueAGuardar;

	return pathDelArchivoDesencriptado;
}

string Vigenere::getPathArchivoEncriptacionPorTipoReporte(int tipoReporte) {

	Configuracion* config = Configuracion::getInstancia();
	string nombreArchivoPorTipo;

	switch (tipoReporte) {

	//Path archivos encriptados
	case (1):
		nombreArchivoPorTipo = config->getPathEncriptado()
				+ "reportePorDistritoEncriptado.txt";
		return nombreArchivoPorTipo;
	case (2):
		nombreArchivoPorTipo = config->getPathEncriptado()
				+ "reportePorListaEncriptado.txt";
		return nombreArchivoPorTipo;
	case (3):
		nombreArchivoPorTipo = config->getPathEncriptado()
				+ "reportePorEleccionEncriptado.txt";
		return nombreArchivoPorTipo;
	case (4):
		nombreArchivoPorTipo = config->getPathEncriptado()
				+ "EncriptadoVigenere.txt";
		return nombreArchivoPorTipo;
	}
}

string Vigenere::getPathArchivoDesencriptacionPorTipoReporte(int tipoReporte) {

	Configuracion* config = Configuracion::getInstancia();
	string nombreArchivoPorTipo;

	switch (tipoReporte) {

	//Path archivos desencriptados
	case (1):
		nombreArchivoPorTipo = config->getPathEncriptado()
				+ "reportePorDistritoDesencriptado.txt";
		return nombreArchivoPorTipo;
	case (2):
		nombreArchivoPorTipo = config->getPathEncriptado()
				+ "reportePorListaDesencriptado.txt";
		return nombreArchivoPorTipo;
	case (3):
		nombreArchivoPorTipo = config->getPathEncriptado()
				+ "reportePorEleccionDesencriptado.txt";
		return nombreArchivoPorTipo;
	case (4):
		nombreArchivoPorTipo = config->getPathEncriptado()
				+ "archivoDesencriptadoVigenere.txt";
	}
}

Vigenere::~Vigenere() {
}
